<?php

namespace app\recharge\controller;

use app\recharge\model\Secret;
use app\recharge\model\Verify;
use app\ux\UtilCurl;
use think\Controller;
use think\Log;
use think\Request;

/**
 * IOS渠道验签
 */
class Ios extends Controller
{

    use \app\recharge\controller\traits\ErrorCodeIOS;

    protected $isSandbox; //沙盒模式
    protected $channel; //当前渠道

    public function _initialize()
    {
        parent::_initialize();

        //沙盒模式(false正式服务器|true沙盒服务器)|当前渠道

        $this->isSandbox = false;
        $this->channel   = 'IOS';

        //验签记录数据模型

        $this->model = new \app\recharge\model\Verify();
        $this->store = new \app\recharge\model\Store();

        //自定义日志初始化

        Log::init([
            'type' => 'File',
            'path' => APP_PATH . 'recharge' . DS . 'logs/',
        ]);
    }

    /**
     * 票据验签请求
     *
     * @param  string  $receipt 苹果票据
     * @return string  苹果服务器验签返回
     */
    public function verifyReceipt($receipt)
    {

        //封装验证票据

        $postData = json_encode(
            array('receipt-data' => $receipt)
        );

        //如果沙盒模式使用苹果测试服,反之使用苹果正式服

        if ($this->isSandbox) {
            $endpoint = 'https://sandbox.itunes.apple.com/verifyReceipt';
        } else {
            $endpoint = 'https://buy.itunes.apple.com/verifyReceipt';
        }

        //设置 URL 和相应的选项
        $defaults = array(
            CURLOPT_POST           => 1,
            CURLOPT_HEADER         => 0,
            CURLOPT_URL            => $endpoint,
            CURLOPT_FRESH_CONNECT  => 1,
            CURLOPT_RETURNTRANSFER => 1,
            CURLOPT_FORBID_REUSE   => 1,
            CURLOPT_TIMEOUT        => 10, //10秒
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_POSTFIELDS     => $postData, // 苹果购买后返回的票据
        );

        //创建新的 cURL 资源

        $ch = curl_init();
        curl_setopt_array($ch, $defaults);

        $result = curl_exec($ch);

        //超时重发
        //
        if ($result === false) {

            if (curl_errno($ch) == CURLE_OPERATION_TIMEDOUT) {

                //超时处理
                $result = curl_exec($ch);

                if ($result === false) {

                    if (curl_errno($ch) == CURLE_OPERATION_TIMEDOUT) {

                        //超时处理
                        $result = curl_exec($ch);
                    }
                }
            }
        }
        //返回错误代码
        //
        if (curl_errno($ch)) {

            curl_close($ch);

            $result = array(
                "code" => curl_errno($ch),
                "msg"  => "cURL Error:" . curl_error($ch),
            );
            return (json_encode($result, JSON_UNESCAPED_UNICODE));
        }

        curl_close($ch);

        return $result;
    }

    /**
     * 请求参数数字签名验证(sign)
     *
     * 匹配的时候返回整数0，失败的时候返回封装的错误信息
     *
     * 1 请求参数字段不全
     * 2 请求参数数字签名不匹配
     *
     * @param  array  $param
     * @return   integer|array
     */
    public function checkSign($param)
    {
        //沙盒测试自动判断
        /*
        if (!array_key_exists('issandbox', $param)) {
        if('true' = $param['issandbox']){
        $this->isSandbox = true;
        }else if('false' = $param['issandbox']){
        $this->isSandbox = false;
        }
        }*/

        //判断键名是否存在

        if (!array_key_exists('data', $param)) {

            $data = array(
                "code" => 1,
                "msg"  => "'data' index don't exist",
            );
            return ($data);
        }

        if (!array_key_exists('sign', $param)) {

            $data = array(
                "code" => 1,
                "msg"  => "'sign' index don't exist",
            );
            return ($data);
        }

        $sign = $param['sign'];
        $json = $param['data'];

        $secret = Secret::getSecret('dragon_app');

        $verify = md5($json . $secret);

        if ($sign === $verify) {

            $data = 0;

        } else {

            $data = array(
                "code" => 2,
                "msg"  => "param's sign doesn't match",
            );
        }
        return ($data);
    }
    /**
     * 票据验证及物品发放请求
     *
     * @param  \think\Request  $request 请求参数
     * @return \think\Response
     */
    public function request(Request $request)
    {

        //接收请求参数

        $param = $request->param();

        //记录验签请求

        Log::record('验签请求:', 'info');
        Log::record(json_encode($param, JSON_UNESCAPED_UNICODE), 'info');

        //请求参数签名验证结果
        //
        $res = $this->checkSign($param);

        //验签失败返回错误信息
        //
        if ($res) {
            return json($res);
        }

        //信息字段解码

        $data = json_decode($param['data'], true);

        //通过平台交易订单号，获取角色ID
        //
        $platformOrderId = $data['platformOrderId'];
        $character_id    = $this->getCharacterIdByOrder($platformOrderId);

        //增加渠道标识,角色/服务器ID
        //
        $data['channel_id']   = $this->channel;
        $data['character_id'] = $character_id;

        //服务器ID-截取平台交易订单号首字符

        $data['server_id'] = substr($platformOrderId, 0, 1);

        //查询请求交易相应的交易记录
        //
        $orderId = $data["orderId"];
        $record  = $this->model->where('orderId', $orderId)->find();

        //订单记录不存在
        //
        if (!$record) {

            //如果交易记录不存在，记录用户验签请求
            //
            $id = $this->model->allowField(true)->save($data);

            //请求验签并发放

            $rtn = $this->verifyReceiptAndIssue($data, $character_id, $id);
            return json($rtn);
        }

        // 如果订单记录存在
        //
        $id = $record->id;

        //查看支付状态
        //
        $payment_status = $record->payment_status;

        if (0 == $payment_status) {

            //如果记录未发放

            $res          = $this->checkIssueByOrderId($orderId);
            $responseData = json_decode($res, true);

            //curl查询失败
            //
            if (array_key_exists('code', $responseData) && ($responseData['code'])) {

                //苹果服务器验签申请并请求发放
                $rtn = $this->verifyReceiptAndIssue($data, $character_id, $id);
                return json($rtn);
            }

            //curl查询成功
            //

            if (0 == $responseData['code']) {

                //如果物品已成功发放
                //
                if (1 == $responseData['num']) {

                    //交易订单发放成功记录更新

                    $res = $this->model->updatePaymentStatusByOrderId($orderId);

                    if (0 == $res['code']) {

                        //订单号存在而且已成功发放

                        $data = array(
                            "code"        => 3,
                            "msg"         => "transaction id exist and payment_status = 1",
                            "transaction" => $orderId,
                        );
                        return json($data);
                    }

                } else if (0 == $responseData['num']) {

                    //如果物品尚未发放,请求验签并发放
                    //
                    $rtn = $this->verifyReceiptAndIssue($data, $character_id, $id);
                    return json($rtn);
                }

            }

        } else if (1 == $payment_status) {

            //订单号存在而且已成功发放

            $data = array(
                "code"        => 3,
                "msg"         => "transaction id exist and payment_status = 1",
                "transaction" => $orderId,
            );
            return json($data);
        }
    }

    /**
     * 物品发放请求url
     *
     * @param    [type] $cid 角色ID
     * @param    [type] $num [description]
     * @param    [type] $orderId [description]
     * @return   [type]
     */
    public function getIssueRequestUrl($cid, $product_id, $orderId)
    {

        $url = "http://115.239.196.59:19998/?sid=144169&mid=20006&serverid=1&cid=1&webgm_cmd=recharge&param=";
        return "{$url}{$cid},{$product_id},'{$orderId}'";
    }

    /**
     * 交易查询url
     *
     * @param  \think\Request  $request
     * @return \think\Response
     */
    public function getIssueVerifyUrl($orderId)
    {

        $url = "http://115.239.196.59:19998/?sid=144169&mid=20005&serverid=1&cid=1&tablename=l_recharge&transaction='{$orderId}'";
        return ($url);
    }
    /**
     * 按订单号做交易订单查询
     *
     * @param    [type] $orderId [description]
     * @return   [type]
     */
    public function checkIssueByOrderId($orderId)
    {
        $curl = new UtilCurl;
        $res  = $curl->get($this->getIssueVerifyUrl($orderId));

        return $res;
    }
    /**
     * 根据平台订单号获取角色ID
     *
     * @return   [type]
     */
    public function getCharacterIdByOrder($platformOrderId)
    {
        $arr = explode('-', $platformOrderId);
        return $arr[1];
    }

    /**
     *  票据验签,之后根据验签结果发放钻石并保存结果
     */
    public function verifyReceiptAndIssue($data, $character_id, $id)
    {
        //票据及交易订单号

        $receipt = $data['receipt'];
        $orderId = $data['orderId'];

        //票据验签请求

        $result = $this->verifyReceipt($receipt);

        //记录票据验签结果

        Log::record('验签结果:', 'info');
        Log::record($result, 'info');
        Log::record("Length of Receipt is : " . strlen($result), 'info');

        $response = json_decode($result, true);

        //dump($responseData); die;

        //验签错误代码转换
        //
        if (array_key_exists('status', $response) && (0 != $response['status'])) {

            if ($response['status']>=21100 && $response['status']<=21199) {

                $error = $this->statusCode('21100');

            }else{

                $error = $this->statusCode($response['status']);
            }

            //如果验签curl请求失败
            //
            $data = array(
                "code" => $response['status'],
                "msg"  => $error,
                "transaction"  => $orderId
            );

            Log::record($error, 'info');
			
            $_temp = [
                'verify_status' => 0,
                'msg'           => $result,
            ];

            //记录验证失败返回信息

            $this->model->allowField(true)
                ->isUpdate(true)
                ->save($_temp, ['id' => $id]);
				
            return $data;
        }

        $responseData = json_decode($result);

        //判断验签结果

        $receiptTemp = $responseData->receipt;
        $in_app      = $receiptTemp->in_app;

        //验签通过 status === 0
        //
        if ($responseData->status === 0) {

            $_temp = [
                'verify_status' => 1,
                'msg'           => $result,
            ];

            //记录验证成功更新记录

            $this->model->allowField(true)
                ->isUpdate(true)
                ->save($_temp, ['id' => $id]);

            $rows = [];

            foreach ($in_app as $item) {

                $product_id     = $item->product_id;
                $transaction_id = $item->transaction_id;

                //匹配交易订单记录验证成功
                //
                if ($orderId == $transaction_id) {

                    $_data = [
                        'quantity'      => (int) $item->quantity,
                        'product_id'    => (int) $item->product_id,
                        'purchase_date' => date("Y-m-d H:i:s", ($item->purchase_date_ms / 1000)),
                    ];

                    $info = $this->store->getInfomationById((int) $item->product_id);

                    //RMB金额换算
                    //
                    if (array_key_exists('amount', $info)) {
                        $_data['amount'] = $info['amount'];
                    }

                    //钻石数换算
                    //
                    if (array_key_exists('diamond', $info)) {
                        $_data['diamond'] = $info['diamond'];
                    }

                    //保存票据验签后得到的明细信息

                    $this->model->allowField(true)
                        ->isUpdate(true)
                        ->save($_data, ['id' => $id]);

                    //玩家物品发放请求
                    //
                    $url  = $this->getIssueRequestUrl($character_id, $product_id, $transaction_id);
                    $curl = new UtilCurl;

                    $rtn = $curl->get($url);

                    Log::record("---------------------------------------------------------------");
                    Log::record("物品发放请求查询结果:");
                    Log::record($rtn);

                    $output = json_decode($rtn, true);

                    if (array_key_exists('code', $output)) {

                        if ($output['code']) {

                            //如果物品发放请求失败
                            //
                            $_item = [
                                'transaction' => $transaction_id,
                                'msg'         => $output['msg'],
                                'code'        => $output['code'],
                            ];

                            array_push($rows, $_item);
                            continue;

                        } else if (0 == $output['code']) {

                            //物品发放请求成功后等待2秒

                            $interval = 2;

                            sleep($interval);

                            //物品发放结果查询

                            $verify_url = $this->getIssueVerifyUrl($transaction_id);
                            $verify     = $curl->get($verify_url);

                            $rtn = json_decode($verify, true);

                            if (array_key_exists('code', $rtn)) {

                                if ($rtn['code']) {

                                    //如果物品发放结果curl查询请求失败
                                    //
                                    $_item = [
                                        'transaction' => $transaction_id,
                                        'msg'         => $rtn['msg'],
                                        'code'        => $rtn['code'],
                                    ];

                                    array_push($rows, $_item);
                                    continue;

                                } else {

                                    if (0 == $rtn['code'] && 1 == $rtn['num']) {

                                        //物品发放记录查询成功
                                        //
                                        $_item = [
                                            'transaction' => $transaction_id,
                                            'msg'         => 'ok',
                                            'code'        => 0,
                                        ];

                                        array_push($rows, $_item);
                                        $this->model->updatePaymentStatusByOrderId($transaction_id);
                                        continue;

                                    } else if (0 == $rtn['code'] && 0 == $rtn['num']) {

                                        //物品发放记录查询结果为未发放
                                        //
                                        $_item = [
                                            'transaction' => $transaction_id,
                                            'msg'         => "transaction issue doesn't excute",
                                            'code'        => 6,
                                        ];

                                        array_push($rows, $_item);
                                        continue;
                                    }

                                }

                            }

                        }

                    }
                }
                //更新验证及发放状态
                //
                $record = Verify::get(function ($query) use ($transaction_id) {
                    $query->where('orderId', $transaction_id);
                });

                if (1 == $record->payment_status) {

                    //物品发放记录查询结果为成功发放
                    //
                    $_item = [
                        'transaction' => $transaction_id,
                        'msg'         => 'ok',
                        'code'        => 0,
                    ];

                    array_push($rows, $_item);
                    continue;

                } else {

                    //物品发放记录查询结果为未发放，玩家请求物品发放
                    //
                    $url  = $this->getIssueRequestUrl($character_id, $product_id, $transaction_id);
                    $curl = new UtilCurl;

                    $rtn = $curl->get($url);

                    $output = json_decode($rtn, true);

                    if (array_key_exists('code', $output)) {

                        if ($output['code']) {

                            //如果物品发放curl请求失败
                            //
                            $_item = [
                                'transaction' => $transaction_id,
                                'msg'         => $output['msg'],
                                'code'        => $output['code'],
                            ];

                            array_push($rows, $_item);
                            continue;
                        }

                        if (0 == $output['code']) {

                            //物品发放请求成功后等待2秒

                            $interval = 2;

                            sleep($interval);

                            //物品发放请求成功后查询发放结果

                            $verify_url = $this->getIssueVerifyUrl($transaction_id);

                            $verify = $curl->get($verify_url);

                            $rtn = json_decode($verify, true);

                            if (array_key_exists('code', $rtn)) {

                                if ($rtn['code']) {

                                    //如果物品发放记录查询curl请求失败
                                    //
                                    $_item = [
                                        'transaction' => $transaction_id,
                                        'msg'         => $rtn['msg'],
                                        'code'        => $rtn['code'],
                                    ];

                                    array_push($rows, $_item);
                                    continue;

                                } else {

                                    if (0 == $rtn['code'] && 1 == $rtn['num']) {

                                        //物品发放记录查询成功
                                        //
                                        $_item = [
                                            'transaction' => $transaction_id,
                                            'msg'         => 'ok',
                                            'code'        => 0,
                                        ];

                                        $this->model->updatePaymentStatusByOrderId($transaction_id);
                                        array_push($rows, $_item);
                                        continue;

                                    } else if (0 == $rtn['code'] && 0 == $rtn['num']) {

                                        //物品发放记录查询结果为未发放
                                        //
                                        $_item = [
                                            'transaction' => $transaction_id,
                                            'msg'         => "transaction doesn't excute",
                                            'code'        => 6,
                                        ];

                                        array_push($rows, $_item);
                                        continue;

                                    }
                                }
                            }
                        }
                    }
                }
            }

            $result = [
                "msg"  => $rows, //data
                "code" => 0,
                "num"  => count($rows), //衍生字段
            ];

            return ($result);

        }
    }
}
